import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

/**
 * @author Aleksey Lagoshin
 * @version 1.0 27/4/2007 16:24:52
 */
public class TextServer extends JFrame {

  public static final String POLICY_REQUEST = "<policy-file-request/>";
  public static final String POLICY_RESPONSE = "<cross-domain-policy>\n" +
                                               "  <allow-access-from domain=\"*\" to-ports=\"*\" />\n" +
                                               "</cross-domain-policy>\n";

  private static int PORT;

  private Socket socket;
  private Vector<SocketThread> activeSockets = new Vector<SocketThread>();

  private JTextArea taMessages = new JTextArea();
  private JTextField tfInput = new JTextField();

  public TextServer(String port) {
    PORT = Integer.valueOf(port);

    setSize(400, 600);

    setLayout(new BorderLayout());

    taMessages.setEditable(false);
    tfInput.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        String msg = tfInput.getText();
        tfInput.setText("");

        for (SocketThread sockThr : activeSockets)
          sockThr.send(msg);
        println(" >> " + msg);
      }
    });

    JScrollPane scrollPane;
    scrollPane = new JScrollPane(taMessages);

    add(scrollPane, BorderLayout.CENTER);
    add(tfInput, BorderLayout.SOUTH);
    setVisible(true);
  }

  public void initialize() {
    new Thread(new Runnable() {
      public void run() {
        try {
          ServerSocket srvSocket = new ServerSocket(PORT);
          taMessages.setText(" ** Listening port " + PORT + "...");
          while (true) {
            socket = srvSocket.accept();
            println(" ** Accepted client from IP - " + socket.getInetAddress());

            SocketThread sockThr = new SocketThread();
            sockThr.setSocket(socket);
            sockThr.start();

            activeSockets.add(sockThr);
          }
        }
        catch (Exception e) {
          e.printStackTrace();
        }
      }
    }).start();
  }

  private void println(String message) {
    taMessages.append(message + '\n');
    taMessages.scrollRectToVisible(new Rectangle(0,taMessages.getHeight()+20,1,1));
  }

  public static void main(String[] args) {
    TextServer txtSrv = new TextServer(args.length > 0 ? args[0] : "777");
    txtSrv.setDefaultCloseOperation(EXIT_ON_CLOSE);
    txtSrv.initialize();
  }

  private class SocketThread extends Thread {

    private Socket socket;

    private InputStreamReader in;
    private OutputStream out;

    public void run() {
      try {
        in = new InputStreamReader(socket.getInputStream(), "UTF-8");
        out = socket.getOutputStream();
        read();
      }
      catch (IOException e) {
        e.printStackTrace();
      }
    }

    private void read() {
      StringBuffer buffer = new StringBuffer();

      int b;
      try {
        while (socket.isConnected()) {
          b = in.read();
          if (b > 0) {
            buffer.append(new Character((char) b));
          }
          else if (b == -1)
            break;
          else {
            println(" << " + buffer.toString());
            if (buffer.toString().equals(POLICY_REQUEST)) {
              println(POLICY_RESPONSE);
              send(POLICY_RESPONSE);
            }
            buffer.setLength(0);
          }
        }
      }
      catch (IOException e) {
        e.printStackTrace();
      }
      finally {
        activeSockets.remove(this);
        println(" ** Client has been disconnected");
      }
    }

    public void send(String message) {
      try {
        out.write(message.getBytes("UTF-8"));
        out.write(0);
      }
      catch (IOException e) {
        e.printStackTrace();
      }
    }

    public void setSocket(Socket socket) {
      this.socket = socket;
    }

  }

}
